package com.sunwayworld.basemodule.common.clickhouse.utils;

import com.sunwayworld.basemodule.common.clickhouse.client.ClickHouseConnection;
import com.sunwayworld.framework.support.PersistableHelper;
import com.sunwayworld.framework.support.domain.BaseData;
import com.sunwayworld.framework.utils.ObjectUtils;
import com.sunwayworld.framework.utils.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.Assert;

import java.sql.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author jiaorg
 * @date 2022-09-14 09:20
 * @description:工具类
 * @version: 1.0.0
 */
public class ClickHouseBaseUtil {
    private static final Logger logger = LogManager.getLogger(ClickHouseBaseUtil.class);
    /**
     * 将首字母变成大写：一般用于通过属性名称反射操作getter，setter方法
     *
     * @param str
     * @return
     */
    public static String capitalize(final String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return str;
        }

        final int firstCodePoint = str.codePointAt(0);
        final int newCodePoint = Character.toTitleCase(firstCodePoint);
        if (firstCodePoint == newCodePoint) {
            // already capitalized
            return str;
        }

        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
        int outOffset = 0;
        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
        for (int inOffset = Character.charCount(firstCodePoint); inOffset < strLen; ) {
            final int codePoint = str.codePointAt(inOffset);
            newCodePoints[outOffset++] = codePoint; // copy the remaining ones
            inOffset += Character.charCount(codePoint);
        }
        return new String(newCodePoints, 0, outOffset);
    }

    public static  <P extends BaseData> List<P> queryBySql(ClickHouseConnection ckconnection, String sql, Class<P> t, Object... params) throws SQLException {
        List<P> list = new ArrayList<>();
        logger.info("sql={}",sql);
        if(params!=null){
            logger.info("sql param={}", StringUtils.join(params,","));
        }
        Connection connection = ckconnection.getConnection();
        try (PreparedStatement ps = connection.prepareStatement(sql)) {
            ps.closeOnCompletion();
            if(params!=null){
                for (int i = 1; i <=params.length; i++) {
                    Object param = params[i-1];
                    if(param instanceof Integer){
                        ps.setInt(i, (Integer) param);
                    }else if(param instanceof Long){
                        ps.setLong(i, (Long) param);
                    }else if(param instanceof String){
                        ps.setString(i, (String) param);
                    }else{
                        ps.setObject(i,param);
                    }
                }
            }
            ResultSet rs = ps.executeQuery();
            while(rs.next()) {
                ResultSetMetaData resultSetMetaData = rs.getMetaData();
                int columnCount = resultSetMetaData.getColumnCount();
                Map<String,Object> row = new HashMap<>();
                for (int i = 1; i <=columnCount; i++) {
                    String colLabel = resultSetMetaData.getColumnLabel(i);
                    Object value = rs.getObject(colLabel);
                    row.put(colLabel,value);
                }
                P p = PersistableHelper.mapToPersistable(row, t);
                list.add(p);
            }
            rs.close();
        } catch (SQLException e) {
            logger.error("execute error:{}",e);
        } finally {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return list;
    }


    public static int deleteBySql(ClickHouseConnection ckconnection, String sql) {
        logger.info("sql={}",sql);
        Connection connection = ckconnection.getConnection();
        try (PreparedStatement ps = connection.prepareStatement(sql)) {
            ps.closeOnCompletion();
            ps.execute(sql);
        } catch (SQLException e) {
            logger.error("execute error:{}",e);
        }
        return 0;
    }

    public static int batchInsert(ClickHouseConnection ckconnection,List<Map<String,Object>> datas,String table,List<String> columns) {
        Assert.hasText(table,"table 不能为空！");
        if (ObjectUtils.isEmpty(datas)) {
            return 0;
        }
        // 构建插入语句sql，占位符value
        StringBuffer sql_insert = new StringBuffer(" insert into ").append(table).append("(");
        StringBuffer sql_value = new StringBuffer("(");

        // 获取类的所有字段，并逐一填充sql和value
        for (String column : columns) {
            sql_insert.append(column).append(",");
            sql_value.append("?").append(",");
        }

        // 完成sql和value的构建
        sql_insert.deleteCharAt(sql_insert.length() - 1).append(")");
        sql_value.deleteCharAt(sql_value.length() - 1).append(")");
        sql_insert.append(" values ").append(sql_value);

        //开始批量插入
        Connection connection = ckconnection.getConnection();
        try {
            PreparedStatement pst = connection.prepareStatement(sql_insert.toString());
            for (Map<String,Object> t : datas) {
                //preparedStatement的占位
                int index = 1;
                for (String column : columns) {
                    // 获取当前字段的值
                    Object getValue = t.get(column);
                    // 日期格式的单独处理
                    if (getValue != null && getValue instanceof LocalDateTime) {
                        getValue =  ((LocalDateTime) getValue).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    }else if (getValue != null && getValue instanceof LocalDate) {
                        getValue =  ((LocalDate) getValue).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    }
                    pst.setObject(index, getValue);
                    index++;
                }
                // 添加到批次
                pst.addBatch();
            }
            // 提交批处理
            int[] res = pst.executeBatch();
            logger.info("新增结果：{}条数据", res.length);
            return res.length;
        } catch (Exception e) {
            logger.error("batchInsert : {}",e);
            throw new RuntimeException(e);
        }finally {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
